interface StorageOpts {
  prefixKey?: string; // 前缀
}

interface StorageSetOpts {
  expires?: number; // 失效时间，以 天 为单位
  isOnce?: boolean; // 是否只一次，读取后删除
}

// 存储封装
class Storage {
  defaultExpires: number;

  prefixKey: string;

  constructor(opts: StorageOpts) {
    this.prefixKey = opts.prefixKey || 'storage';
  }

  // 存数据前处理
  _getInputData(data: unknown, options: StorageSetOpts) {
    const _data = {
      data,
      keyInfo: Object.assign(options, {
        timestamp: new Date().getTime(),
      }),
    };

    return JSON.stringify(_data);
  }

  // 取数据后处理
  _getOutputData(data: any) {
    try {
      const _data = JSON.parse(data);
      return _data;
    } catch (error) {
      console.error('本地存储数据损坏，请重置!!', error)
      return {}
    }
  }

  // 获取_key的数据 => { data, keyInfo }
  _getData(_key: string) {
    const _data = localStorage.getItem(_key);

    return this._getOutputData(_data);
  }

  // 特殊处理key
  _getKey(key: string) {
    return `__${this.prefixKey}__${key}__`;
  }

  _remove(_key: string) {
    localStorage.removeItem(_key);
  }

  // 是否有效期内
  _isExpired(_key: string) {
    const { keyInfo } = this._getData(_key);
    const { expires, timestamp } = keyInfo;

    if (!expires) {
      return false;
    }

    return timestamp + expires * 24 * 3600 * 1000 - new Date().getTime() < 0;
  }

  // 是否只读取一次
  _isOnce(_key: string) {
    const { keyInfo } = this._getData(_key);
    const { isOnce } = keyInfo;

    return !!isOnce;
  }

  get(key: string) {
    const _key = this._getKey(key);
    const _data = this._getData(_key);

    if (!_data) {
      return null;
    }

    const isExpired = this._isExpired(_key);
    const isOnce = this._isOnce(_key);

    // 删除已过期或者只读取一次的_key
    if (isExpired || isOnce) {
      this._remove(_key);
    }

    return isExpired ? null : _data.data;
  }

  set(key: string, data: any, options = {} as StorageSetOpts) {
    const _key = this._getKey(key);
    const _data = this._getInputData(data, options);

    localStorage.setItem(_key, _data);
  }

  remove(key: string) {
    const _key = this._getKey(key);

    this._remove(_key);
  }

  once(key: string, data: any, options = {}) {
    const _key = this._getKey(key);
    const _data = this._getInputData(
      data,
      Object.assign(options, {
        isOnce: true,
      }),
    );

    localStorage.setItem(_key, _data);
  }
}
const storage = new Storage({} as StorageOpts);
export default storage;

// Token 的存储封装
const TokenKey = 'Token';
export function getToken() {
  return storage.get(TokenKey);
}
export function setToken(token: string) {
  return storage.set(TokenKey, token)
}
export function removeToken() {
  return storage.remove(TokenKey);
}
